#include "BasicThread.h"

#include <assert.h>

//#if defined(WIN32)
//#include <process.h>
//typedef unsigned( __stdcall *PTHREAD_START) (void*);
//
//#define chBEGINTHREADEX( psa, cbStack, pfnStartAddr,\
//	pvParam, fdwCreate, pdwThreadID) \
//	( (HANDLE) _beginthreadex(       \
//	(void*) (psa),           \
//	(unsigned) (cbStack),    \
//	(PTHREAD_START) (pfnStartAddr),\
//	(void*) (pvParam),       \
//	(unsigned) (fdwCreate),  \
//	(unsigned*) (pdwThreadID)) )
//#else
//#endif

namespace utility
{
	BasicThread::BasicThread(void)
	{
		m_hThread = NULL;
		m_dwThreadID = 0;
		m_hMutipleObjects[0] = CreateEvent( NULL, TRUE, FALSE, NULL );
	}

	BasicThread::~BasicThread(void)
	{
		if( m_hMutipleObjects[0] != NULL )
		{
			CloseHandle( m_hMutipleObjects[0] );
		}
	}

	bool BasicThread::CreateThread( void * psa, unsigned cbStatck, PTHREAD_START pfn, void * param, unsigned fdwCreate )
	{
		//m_param.m_arg = param;
		ResetEvent( m_hMutipleObjects[0] );
		m_hThread = chBEGINTHREADEX( psa, cbStatck, pfn, param, fdwCreate, &m_dwThreadID );
		if( m_hThread == NULL )
			return false;
		return true;
	}

	bool BasicThread::IsTheadStop( int nWaitTime /*= 0 */ )
	{
		DWORD dwRet = WaitForSingleObject( m_hMutipleObjects[0], nWaitTime );
		if( dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED || dwRet == WAIT_FAILED )
			return true;
		else
			return false;
	}

	bool BasicThread::IsSingleWaiteThreadStop( unsigned int nWaitTime /*= 0 */ )
	{
		DWORD dwRet = WaitForSingleObject( m_hMutipleObjects[0], nWaitTime );
		if( dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED || dwRet == WAIT_FAILED )
			return true;
		else
			return false;
	}

	bool BasicThread::IsMultipleWaitThreadStop( int nCount, const PHANDLE lpHandles, unsigned int * pnResult, unsigned int nWaitTime /*= 0 */ )
	{
		assert( nCount < BASIC_MAXIMUM_WAIT_OBJECTS );
		memcpy_s( &m_hMutipleObjects[1], (BASIC_MAXIMUM_WAIT_OBJECTS-1)*sizeof(HANDLE), lpHandles, nCount*sizeof(HANDLE) );
		DWORD dwRet = WaitForMultipleObjects( nCount+1, m_hMutipleObjects, FALSE, nWaitTime );
		if( dwRet == WAIT_TIMEOUT )
		{
			*pnResult = dwRet;
			return false;
		}
		else if( dwRet == WAIT_FAILED )
		{
			*pnResult = dwRet;
			return true;
		}
		else if( dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED_0 )
		{
			return true;
		}
		else
		{
			*pnResult = dwRet-1;// 0-nCount
			return false;
		}
	}

	void BasicThread::StopThread( bool bAsyn/*=false */ )
	{
		SetEvent( m_hMutipleObjects[0] );
		if( !bAsyn )
		{
			if( m_hThread != NULL )
			{
				WaitForSingleObject( m_hThread, INFINITE );
				CloseHandle( m_hThread );
				m_hThread = NULL;
			}
		}
	}

	void BasicThread::WaitThreadStop()
	{
		if( m_hThread != NULL )
		{
			WaitForSingleObject( m_hThread, INFINITE );
			CloseHandle( m_hThread );
			m_hThread = NULL;
		}
	}

	void BasicThread::ExitThead( int nExitCode /*= -1 */ )
	{
		::ExitThread( nExitCode );
		if( m_hThread != NULL )
		{
			CloseHandle( m_hThread );
			m_hThread = NULL;
		}
	}

	bool BasicThread::TerminateThread( int nExitCode /*= -1 */ )
	{
		if( m_hThread != NULL )
		{
			BOOL bRes = ::TerminateThread( m_hThread, nExitCode );
			CloseHandle( m_hThread );
			m_hThread = NULL;
			return bRes;
		}
		else
			return true;
	}

	int BasicThread::GetExitCode()
	{
		if( m_hThread == NULL )
			return 0;

		DWORD dwRetCode = 0;
		::GetExitCodeThread( m_hThread, &dwRetCode );
		return dwRetCode;
	}
}
